玩转Openvswitch之综合篇
这是一个Openvswitch的综合实例。
1. 创建一个bridge
ovs-vsctl add-br helloworld
创建四个veth pair
ip link add first_br type veth peer name first_if
ip link add second_br type veth peer name second_if
ip link add third_br type veth peer name third_if
ip link add forth_br type veth peer name forth_if
添加四个端口port,ofport_request是指定端口号
ovs-vsctl add-port helloworld first_br -- set Interface first_br ofport_request=1
ovs-vsctl add-port helloworld second_br -- set Interface second_br ofport_request=2
ovs-vsctl add-port helloworld third_br -- set Interface third_br ofport_request=3
ovs-vsctl add-port helloworld forth_br -- set Interface forth_br ofport_request=4
新添加的port都是出于DOWN的状态,设成up
ip link set first_if up
ip link set first_br up
ip link set second_br up
ip link set second_if up
ip link set third_if up
ip link set third_br up
ip link set forth_br up
ip link set forth_if up
2. 实现第一个Table 0,Admission control
包进入vswitch的时候首先进入Table 0,我们在这里可以设定规则,控制那些包可以进入,那些包不可以进入。
multicast的不允许进入
ovs-ofctl add-flow helloworld "table=0, dl_src=01:00:00:00:00:00/01:00:00:00:00:00, actions=drop"
STP的也不接受
ovs-ofctl add-flow helloworld "table=0, dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0, actions=drop"
添加最后一个flow,这个flow的priority低于default,如果上面两个不匹配,则我们进入table 1
ovs-ofctl add-flow helloworld "table=0, priority=0, actions=resubmit(,1)"
测试Table 0
不满足条件DROP
ovs-appctl ofproto/trace helloworld in_port=1,dl_dst=01:80:c2:00:00:05
满足条件RESUBMIT
ovs-appctl ofproto/trace helloworld in_port=1,dl_dst=01:80:c2:00:00:10
3. 实现第二个Table 1:VLAN Input Processing
添加一个最低优先级的DROP的规则
ovs-ofctl add-flow helloworld "table=1, priority=0, actions=drop"
对于port 1,是trunk口,无论有没有VLAN Header都接受
ovs-ofctl add-flow helloworld "table=1, priority=99, in_port=1, actions=resubmit(,2)"
对于port 2, 3, 4, 我们希望没有VLAN Tag,然后我们给打上VLAN Tag
ovs-ofctl add-flows helloworld - <<'EOF'
table=1, priority=99, in_port=2, vlan_tci=0, actions=mod_vlan_vid:20, resubmit(,2)
table=1, priority=99, in_port=3, vlan_tci=0, actions=mod_vlan_vid:30, resubmit(,2)
table=1, priority=99, in_port=4, vlan_tci=0, actions=mod_vlan_vid:30, resubmit(,2)
EOF
测试Table 1
从port 1进入,tag为5
ovs-appctl ofproto/trace helloworld in_port=1,vlan_tci=5
从port 2进入,没有打Tag的
ovs-appctl ofproto/trace helloworld in_port=2
从port 2进入,带Tag 5的
ovs-appctl ofproto/trace helloworld in_port=2,vlan_tci=5
4. 实现第三个Table 2: MAC, VLAN learning for ingress port
对于普通的switch,都会有这个学习的过程,当一个包到来的时候,由于包里面有MAC,VLAN Tag,以及从哪个口进来的这个信息。
于是switch学习后,维护了一个表格port –> MAC –> VLAN Tag。
这样以后如果有需要发给这个MAC的包,不用ARP,switch自然之道应该发给哪个port,应该打什么VLAN Tag。
OVS也要学习这个,并维护三个之间的mapping关系。
ovs-ofctl add-flow helloworld "table=2 actions=learn(table=10, NXM_OF_VLAN_TCI[0..11], NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15]), resubmit(,3)"
learn表示这是一个学习的action
table 10,这是一个MAC learning table,学习的结果会放在这个table中。
NXM_OF_VLAN_TCI这个是VLAN Tag,在MAC Learning table中,每一个entry都是仅仅对某一个VLAN来说的,不同VLAN的learning table是分开的。在学习的结果的entry中,会标出这个entry是对于哪个VLAN的。
NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]这个的意思是当前包里面的MAC Source Address会被放在学习结果的entry里面的dl_dst里面。这是因为每个switch都是通过Ingress包来学习,某个MAC从某个port进来,switch就应该记住以后发往这个MAC的包要从这个port出去,因而MAC source address就被放在了Mac destination address里面,因为这是为发送用的。
NXM_OF_IN_PORT[]->NXM_NX_REG0将portf放入register.
一般对于学习的entry还需要有hard_timeout,这是的每个学习结果都会expire,需要重新学习。
测试Table 2:
从port 1来一个vlan为20的mac为50:00:00:00:00:01的包
ovs-appctl ofproto/trace helloworld in_port=1,vlan_tci=20,dl_src=50:00:00:00:00:01 -generate
ovs-ofctl dump-flows helloworld
table 10多了一条,vlan为20,dl_dst为50:00:00:00:00:01,发送的时候从port 1出去
从port 2进来,被打上了vlan 20,mac为50:00:00:00:00:02
ovs-appctl ofproto/trace helloworld in_port=2,dl_src=50:00:00:00:00:02 -generate
5. 实现第四个table 3: Look Up Destination Port
在table 2中,vswtich通过进入的包,学习了vlanid –> mac –> port的映射后,对于要发送的包,可以根据学习到的table 10里面的内容,根据destination mac和vlan,来找到相应的port发送出去,而不用每次都flood。
ovs-ofctl add-flow helloworld "table=3 priority=50 actions=resubmit(,10), resubmit(,4)"
添加这条规则,首先到table 10中查找learn table entry,如果找不到则到table 4
如果包本身就是multicast的或者broadcast的,则不用去table 10里面取查找。
ovs-ofctl add-flow helloworld "table=3 priority=99 dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,4)"
测试Table 3:
ovs-appctl ofproto/trace helloworld in_port=1,dl_vlan=20,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01 -generate
由于目标地址f0:00:00:00:00:01没有在table 10中找到,因而到达table 4。
但是这次测试使得table 10中学习到了mac地址90:00:00:00:00:01
ovs-appctl ofproto/trace helloworld in_port=2,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01 -generate
因为刚才学习到了mac地址f0:00:00:00:00:01,所以这次在table 10中找到了这条记录,这次同时也学习到了mac地址90:00:00:00:00:01
再发送第一次的包
ovs-appctl ofproto/trace helloworld in_port=1,dl_vlan=20,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01 -generate
也在table 10中找到了记录
6. 实现第五个table 4: Output Processing
这个时候,register 0中包含了output port,如果是0则说明是flood
对于port 1来讲,是trunk port,所以携带的vlan tag就让他带着,从port 1出去
ovs-ofctl add-flow helloworld "table=4 reg0=1 actions=1"
对于port 2来讲,是vlan 20的,然而出去的时候,vlan tag会被抹掉,从port 2发出去
对于port 3, 4来讲,是vlan 30的,然而出去的时候,vlan tag会被抹掉,从port 3, 4出去
ovs-ofctl add-flows helloworld - <<'EOF'
table=4 reg0=2 actions=strip_vlan,2
table=4 reg0=3 actions=strip_vlan,3
table=4 reg0=4 actions=strip_vlan,4
EOF
对于broadcast来讲,我们希望一个vlan的broadcast仅仅在这个vlan里面发送,不影响其他的vlan
ovs-ofctl add-flows helloworld - <<'EOF'
table=4 reg0=0 priority=99 dl_vlan=20 actions=1,strip_vlan,2
table=4 reg0=0 priority=99 dl_vlan=30 actions=1,strip_vlan,3,4
table=4 reg0=0 priority=50 actions=1
EOF
所以对于register = 0的,也即是broadcast的,属于vlan 20的,则从port 1, 2出去,属于vlan 30的,则从port 1, 3, 4出去。
测试Table 4
如果是一个port 1来的vlan 30的broadcast
ovs-appctl ofproto/trace helloworld in_port=1,dl_dst=ff:ff:ff:ff:ff:ff,dl_vlan=30
结果是port 1就不发送了,发送给了port 3, 4
ovs-appctl ofproto/trace helloworld in_port=3,dl_dst=ff:ff:ff:ff:ff:ff
接着测试mac learning
ovs-appctl ofproto/trace helloworld in_port=1,dl_vlan=30,dl_src=10:00:00:00:00:01,dl_dst=20:00:00:00:00:01 -generate
由于这两个地址没有出现过,则除了进行学习以外,广播发送给port 3,4
ovs-appctl ofproto/trace helloworld in_port=4,dl_src=20:00:00:00:00:01,dl_dst=10:00:00:00:00:01 -generate
回复的时候,由于学习过了,则仅仅从port 1发送出去
ovs-appctl ofproto/trace helloworld in_port=1,dl_vlan=30,dl_src=10:00:00:00:00:01,dl_dst=20:00:00:00:00:01 -generate
由于在回复中进行了学习,因而发送的时候,仅仅发送port 4